package org.zoomdev.zoom;

import com.alibaba.fastjson2.JSONWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.zoomdev.zoom.security.Sensitive;

// ASM 指令封装辅助类
public class JsonAsmHelper {
    private final MethodVisitor mv;
    private final String className;

    public JsonAsmHelper(MethodVisitor mv, String className) {
        this.mv = mv;
        this.className = className;
    }

    public void startObject() {
        mv.visitVarInsn(Opcodes.ALOAD, 1); // jsonWriter
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
                Type.getInternalName(JSONWriter.class), "startObject", "()V", true);
    }

    public void endObject() {
        mv.visitVarInsn(Opcodes.ALOAD, 1); // jsonWriter
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
                Type.getInternalName(JSONWriter.class), "endObject", "()V", true);
    }

    public void writeRaw(String value) {
        mv.visitVarInsn(Opcodes.ALOAD, 1); // jsonWriter
        mv.visitLdcInsn(value);
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
                Type.getInternalName(JSONWriter.class), "writeRaw", "(Ljava/lang/String;)V", true);
    }

    public void writeColon() {
        mv.visitVarInsn(Opcodes.ALOAD, 1); // jsonWriter
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
                Type.getInternalName(JSONWriter.class), "writeColon", "()V", true);
    }

    public void writeComma() {
        mv.visitVarInsn(Opcodes.ALOAD, 1); // jsonWriter
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
                Type.getInternalName(JSONWriter.class), "writeComma", "()V", true);
    }

    public void writeString() {
        mv.visitVarInsn(Opcodes.ALOAD, 1); // jsonWriter
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
                Type.getInternalName(JSONWriter.class), "writeString", "(Ljava/lang/String;)V", true);


    }

    public void writeBool() {
        mv.visitVarInsn(Opcodes.ALOAD, 1); // jsonWriter
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
                Type.getInternalName(JSONWriter.class), "writeBool", "(Z)V", true);


    }

    // 加载 sensitives[index] 到栈顶
    public void loadSensitiveArrayElement(int index) {
        // 加载 this
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        // 获取 this.sensitives 字段
        mv.visitFieldInsn(Opcodes.GETFIELD, className, "sensitives",
                "[L" + Type.getInternalName(Sensitive.class) + ";");
        // 根据索引值选择最优指令
        loadInteger(index);
        // 从数组中获取元素
        mv.visitInsn(Opcodes.AALOAD);
    }

    // 通用整数加载方法（可复用）
    public void loadInteger(int value) {
        if (value >= -1 && value <= 5) {
            // 使用 ICONST_x 指令（最高效）
            switch (value) {
                case -1:
                    mv.visitInsn(Opcodes.ICONST_M1);
                    break;
                case 0:
                    mv.visitInsn(Opcodes.ICONST_0);
                    break;
                case 1:
                    mv.visitInsn(Opcodes.ICONST_1);
                    break;
                case 2:
                    mv.visitInsn(Opcodes.ICONST_2);
                    break;
                case 3:
                    mv.visitInsn(Opcodes.ICONST_3);
                    break;
                case 4:
                    mv.visitInsn(Opcodes.ICONST_4);
                    break;
                case 5:
                    mv.visitInsn(Opcodes.ICONST_5);
                    break;
            }
        } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
            // 使用 BIPUSH 指令（1字节操作数）
            mv.visitIntInsn(Opcodes.BIPUSH, value);
        } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
            // 使用 SIPUSH 指令（2字节操作数）
            mv.visitIntInsn(Opcodes.SIPUSH, value);
        } else {
            // 对于大整数，使用 LDC 指令（从常量池加载）
            mv.visitLdcInsn(value);
        }
    }

    // 调用 toSensitiveString 方法
    public void callToSensitiveString() {
        String descriptor = "(Ljava/lang/String;)Ljava/lang/String;";
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
                Type.getInternalName(Sensitive.class), "toSensitiveString", descriptor, true);
    }
}
